/*
 * This file is a part of the SWFer project.
 *
 * Copyright (C) 2012 Michael Bradshaw <mjbshaw@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#ifndef BITFIELD_HPP
#define BITFIELD_HPP

#include "BasicBaseTypes.hpp"

#include <limits>

namespace swfer
{

template <typename T>
T bitLog2(T value)
{
	// TODO: is this how I really want to handle this case?
	if (value < 0) value = -value;

    T i = 0;
    while (value >>= 1)
    {
        ++i;
    }

    return i;
}

// TODO: make signed bit field
// TODO: make a float bit field
// TODO: change name so this is clear it's an unsigned bit field
template <uint8_t N>
struct BitField
{
	// Note: these constructors are useful, but prevent the bit field from
	// being in unions (like for Tag<DEFINE_SOUND>), so I took them out...
	/*
    BitField() : value(0)
    {
    }

    BitField(uint32_t v) : value(v & (~(std::numeric_limits<uint32_t>::max() << N)))
    {
    }
	*/
	
    BitField<N>& operator = (uint32_t v)
    {
        value = v & (~(std::numeric_limits<uint32_t>::max() << N));
        return *this;
    }
	
    BitField<N>& operator <<= (uint32_t v)
    {
        value = (value << v) & (~(std::numeric_limits<uint32_t>::max() << N));
        return *this;
    }

    uint32_t operator << (uint32_t v) const
    {
        return value << v;
    }

    BitField<N>& operator |= (uint32_t v)
    {
        value = (value | v) & (~(std::numeric_limits<uint32_t>::max() << N));
        return *this;
    }

    uint32_t operator | (uint32_t v) const
    {
        return value | v;
    }

    operator uint32_t() const
    {
        return value & (~(std::numeric_limits<uint32_t>::max() << N));
    }

    uint32_t value;
    const static uint8_t bits = N;
};

template <>
struct BitField<0>
{
    BitField() : value(0), bits(0)
    {
    }

    BitField(uint32_t v) : value(v), bits(0) // TODO: set bits to log2(v) + 1?
    {
    }

    BitField<0>& operator = (uint32_t v)
    {
        // TODO: set bits to log2(v) + 1?
        value = v & (~(std::numeric_limits<uint32_t>::max() << bits));
        return *this;
    }

    BitField<0>& operator <<= (uint32_t v)
    {
        // TODO: set bits to log2(v) + 1?
        value = (value << v) & (~(std::numeric_limits<uint32_t>::max() << bits));
        return *this;
    }

    uint32_t operator << (uint32_t v) const
    {
        return value << v;
    }

    BitField<0>& operator |= (uint32_t v)
    {
        // TODO: set bits to log2(v) + 1?
        value = (value | v) & (~(std::numeric_limits<uint32_t>::max() << bits));
        return *this;
    }

    uint32_t operator | (uint32_t v) const
    {
        return value | v;
    }

    operator uint32_t() const
    {
        return value & (~(std::numeric_limits<uint32_t>::max() << bits));
    }

    uint32_t value;
    uint8_t bits;
};

}

#endif
